
def parse_mime_type(mime_type):
    type = mime_type.split(';')
    (type, plist,) = (type[0], type[1:])
    try:
        (type, subtype,) = type.split('/', 1)
    except ValueError:
        (type, subtype,) = ((type.strip() or '*'), '*')
    else:
        type = (type.strip() or '*')
        subtype = (subtype.strip() or '*')
    params = {}
    for param in plist:
        param = param.split('=', 1)
        if (len(param) == 2):
            (key, value,) = (param[0].strip(), param[1].strip())
            if (key and value):
                params[key] = value

    return (type,
     subtype,
     params)



def parse_media_range(range):
    (type, subtype, params,) = parse_mime_type(range)
    try:
        if not 0 <= float(params['q']) <= 1:
            raise ValueError
    except (KeyError, ValueError):
        params['q'] = '1'
    return (type,
     subtype,
     params)



def fitness_and_quality_parsed(mime_type, parsed_ranges):
    (best_fitness, best_fit_q,) = (-1, 0)
    (target_type, target_subtype, target_params,) = parse_media_range(mime_type)
    for (type, subtype, params,) in parsed_ranges:
        if (((type == target_type) or ((type == '*') or (target_type == '*'))) and ((subtype == target_subtype) or ((subtype == '*') or (target_subtype == '*')))):
            fitness = 0
            if (type == target_type):
                fitness += 100
            if (subtype == target_subtype):
                fitness += 10
            for key in target_params:
                if ((key != 'q') and (key in params)):
                    if (params[key] == target_params[key]):
                        fitness += 1

            if (fitness > best_fitness):
                best_fitness = fitness
                best_fit_q = params['q']

    return (best_fitness, float(best_fit_q))



def quality_parsed(mime_type, parsed_ranges):
    return fitness_and_quality_parsed(mime_type, parsed_ranges)[1]



def quality(mime_type, ranges):
    parsed_ranges = map(parse_media_range, ranges.split(','))
    return quality_parsed(mime_type, parsed_ranges)



def best_match(supported, header):
    if not supported:
        return ''
    else:
        parsed_header = map(parse_media_range, header.split(','))
        best_type = max([ (fitness_and_quality_parsed(mime_type, parsed_header), -n) for (n, mime_type,) in enumerate(supported) ])
        return ((best_type[0][1] and supported[-best_type[1]]) or '')



def desired_matches(desired, header):
    parsed_ranges = map(parse_media_range, header.split(','))
    return [ mimetype for mimetype in desired if quality_parsed(mimetype, parsed_ranges) ]



